package com.dyx.source.util;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

public class ReadUtils {

    public static void readFromClient(SocketChannel socketChannel,
                                      SelectionKey selectionKey) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int len = 0;
        // 需要注意的是：
        // 当我们telnet切断客户端链接时，会一直出发SocketChannel读就绪事件。会出现循环读问题。或者客户端断开执行完毕断开连接时
        // “当客户端的链接异常断开，此时代表这个链接的channel一直处于readable的状态，如何检查链接已断开呢？
        // 一段时间的试验发现，链接断开后，虽然该channel的ready operation是OP_READ，但是此时channel.read(buffer)返回-1，此时可以增加一个判断”。
        System.out.println("socketChannel-->" + socketChannel + ",hashcode-->" + System.identityHashCode(socketChannel) + " is still Connected?" + socketChannel.isConnected());
        // 10.3 将socketChannel中的数据读取到缓冲区当中
        while ((len = socketChannel.read(buffer)) > 0) {
            System.out.println("读取数据的长度为len-->" + len);
            // 10.4 转换为读模式
            buffer.flip();
            byte[] bytes = new byte[buffer.limit() - buffer.position()];
            buffer.get(bytes);
            System.out.print("byte data is -->" + Arrays.toString(bytes)
                    + ",byte to string data is -->" + new String(bytes));
            // 10.5 循环读取的情况下，需要将buffer清空，否则会有数据的重复
            buffer.clear();
        }

        // 其实read返回0有3种情况：
        // 一是某一时刻socketChannel中当前（注意是当前）没有数据可以读，这时会返回0，
        // 其次是bytebuffer的position等于limit了，即bytebuffer的remaining等于0，这个时候也会返回0，
        // 最后一种情况就是客户端的数据发送完毕了（注意看后面的程序里有这样子的代码），
        // 这个时候客户端想获取服务端的反馈调用了recv函数，若服务端继续read，这个时候就会返回0。
        if (len == 0) {
            System.out.println("读取数据的长度为len-->" + len);
        }

        // read返回-1说明客户端的数据发送完毕，并且主动的close socket。
        // 所以在这种场景下，（服务器程序）你需要关闭socketChannel并且取消key，最好是退出当前函数。
        // 注意，这个时候服务端要是继续使用该socketChannel进行读操作的话，就会抛出“远程主机强迫关闭一个现有的连接”的IO异常。
        if (len < 0) {
            System.out.println("读取数据的长度为len-->" + len);
            System.out.println("socketChannel" + socketChannel + "closed");
            socketChannel.close();
            selectionKey.cancel();
        }
    }
}
